package be.sc.classicnetwork.service.impl;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.springframework.transaction.annotation.Transactional;

import be.sc.classicnetwork.annotation.RefreshCache;
import be.sc.classicnetwork.dao.CarDao;
import be.sc.classicnetwork.dao.GenericDao;
import be.sc.classicnetwork.dao.PaginationSearchResult;
import be.sc.classicnetwork.model.Car;
import be.sc.classicnetwork.model.Contact;
import be.sc.classicnetwork.model.Image;
import be.sc.classicnetwork.model.Location;
import be.sc.classicnetwork.model.Make;
import be.sc.classicnetwork.model.Option;
import be.sc.classicnetwork.model.Site;
import be.sc.classicnetwork.model.Type;
import be.sc.classicnetwork.service.CarService;
import be.sc.classicnetwork.service.ServiceLocator;
import be.sc.classicnetwork.util.Assert;

/**
 * CarService implementation.
 */
@Transactional
public class CarServiceImpl extends GenericServiceImpl<Car> implements
		CarService {

	private ServiceLocator serviceLocator;

	/**
	 * Constructor.
	 */
	public CarServiceImpl(GenericDao<Car> dao) {
		super(dao);
	}

	/**
	 * getCarDao.
	 */
	private CarDao getCarDao() {
		return (CarDao) getDao();
	}

	/**
	 * @see be.sc.classicnetwork.service.impl.GenericServiceImpl#findByIdFull(int)
	 *      TODO this was done for AOP; find another way (without writing this
	 *      method)
	 */
	@Override
	public Car findByIdFull(String id) {
		return super.findByIdFull(id);
	}

	/**
	 * @see be.sc.classicnetwork.service.CarService#saveOrUpdate(Car, Image[],
	 *      Option[])
	 */
	@RefreshCache
	public Car saveOrUpdate(Car car, Image[] images2delete,
			Collection<Option> options) {
		Assert.notNull(images2delete);
		Assert.notNull(options);

		car.removeImages(images2delete);
		car.setOptions(new HashSet<Option>(options));
		car.addDefaultImageIfNone();
		car.setThumbIfNone();

		return super.saveOrUpdate(car);
	}

	/**
	 * @see be.sc.classicnetwork.service.CarService#countMakes(boolean)
	 */
	public Collection<Object[]> countMakes(boolean enableFilterPublished) {
		return getCarDao().countMakes(enableFilterPublished);
	}

	/**
	 * @see be.sc.classicnetwork.service.CarService#findByMake(int, int,
	 *      boolean, be.sc.classicnetwork.model.Make)
	 */
	public PaginationSearchResult findByMake(int first, int max,
			boolean enableFilterPublished, Make make) {
		return getCarDao().findByMake(first, max, enableFilterPublished, make);
	}

	/**
	 * @see be.sc.classicnetwork.service.CarService#findByModelOrMakeLike(int,
	 *      int, boolean, java.lang.String)
	 */
	public PaginationSearchResult findByModelOrMakeLike(int offset,
			int maxPageItems, boolean enableFilterPublished, String model) {
		return getCarDao().findByModelOrMakeLike(offset, maxPageItems,
				enableFilterPublished, model);
	}

	/**
	 * @see be.sc.classicnetwork.service.CarService#findImageById(int)
	 */
	public Image findImageById(String id) {
		return getCarDao().findImageById(id);
	}

	/**
	 * @see be.sc.classicnetwork.service.CarService#findContactsForNotification(int)
	 */
	public Collection<Contact> findContactsForNotification(String carId) {
		return getCarDao().findContactsForNotification(carId);
	}

	/**
	 * @see be.sc.classicnetwork.service.CarService#findAll(int, int, boolean)
	 */
	public PaginationSearchResult findAll(int first, int max,
			boolean enableFilterPublished) {
		return getCarDao().findAll(first, max, enableFilterPublished);
	}

	/**
	 * @see be.sc.classicnetwork.service.CarService#getCache()
	 */
	@SuppressWarnings("unchecked")
	public Map getCache() {
		HashMap cache = new HashMap();
		HashMap codes = new HashMap();
		HashMap allCars = new HashMap();
		HashMap filteredCars = new HashMap();

		// get the codes
		codes.put("optionList", this.serviceLocator.getCodeService().findAll(
				Option.class));
		codes.put("typeList", this.serviceLocator.getCodeService().findAll(
				Type.class));
		codes.put("siteList", this.serviceLocator.getCodeService().findAll(
				Site.class));
		codes.put("locationList", this.serviceLocator.getCodeService().findAll(
				Location.class));
		codes.put("makeList", this.serviceLocator.getCodeService().findAll(
				Make.class));

		// get the cars
		allCars.put("carCount", findAll(0, 1, false).getCount());
		allCars.put("makeCount", countMakes(false));

		// get the filtered cars
		filteredCars.put("carCount", findAll(0, 1, true).getCount());
		filteredCars.put("makeCount", countMakes(true));

		// get the contacts
		cache.put("contactList", this.serviceLocator.getContactService()
				.findAll(0, 0));

		cache.put("codes", codes);
		cache.put("allCars", allCars);
		cache.put("filteredCars", filteredCars);

		return cache;
	}

	public ServiceLocator getServiceLocator() {
		return serviceLocator;
	}

	public void setServiceLocator(ServiceLocator serviceLocator) {
		this.serviceLocator = serviceLocator;
	}

}
